<template>
  <Teleport :to="teleportTo" :disabled="teleportDisabled">
    <el-dialog
      v-bind="$attrs"
      ref="dialogRef"
      :modelValue="modelValue"
      :title="title"
      :width="width"
      :modal="modal"
      :modalClass="dialogClass"
      :appendToBody="false"
      :lockScroll="lockScroll"
      :openDelay="openDelay"
      :closeDelay="closeDelay"
      :closeOnClickModal="closeOnClickModal"
      :closeOnPressEscape="closeOnPressEscape"
      :showClose="false"
      :beforeClose="beforeClose"
      :draggable="false"
      :overflow="false"
      :center="center"
      :alignCenter="false"
      :destroyOnClose="destroyOnClose"
      :zIndex="zIndex"
      :headerAriaLevel="headerAriaLevel"
      @update:modelValue="updateModelValue"
      @open="handleOpen"
      @opened="handleOpened"
      @close="handleClose"
      @closed="handleClosed"
      @openAutoFocus="handleOpenAutoFocus"
      @closeAutoFocus="handleCloseAutoFocus"
    >
      <template #header="{ close, titleId, titleClass }">
        <div
          :style="headerStyle"
          class="baf-modal-header"
          @mousedown="handleHeaderMousedown"
          @touchstart="handleHeaderTouchstart"
        >
          <div class="baf-modal-title" :style="titleStyle">
            <slot
              name="header"
              :close="close"
              :titleId="titleId"
              :titleClass="titleClass"
            >
              {{ title }}
            </slot>
          </div>
          <!-- 关闭图标 -->
          <div
            v-if="showClose"
            class="baf-modal-close"
            :style="closeBtnStyle"
            @click="updateModelValue(false)"
          >
            <slot name="closeIcon">
              <ElIcon>
                <component v-if="closeIcon" :is="closeIcon" />
                <Close v-else />
              </ElIcon>
            </slot>
          </div>
        </div>
      </template>
      <template v-if="$slots.footer" #footer>
        <div class="baf-modal-footer" :style="footerStyle">
          <slot name="footer"></slot>
        </div>
      </template>
      <template #default>
        <div class="baf-modal-body" :style="bodyStyle">
          <slot></slot>
        </div>
      </template>
    </el-dialog>
  </Teleport>
</template>

<script setup>
  /**
   * @typedef {import('vue').CSSProperties} CSSProperties
   * 用于类型提示的 CSS 属性集合类型
   */
  import { ref, computed } from 'vue';
  import { dialogProps, dialogEmits } from 'element-plus';
  import { Close } from '@element-plus/icons-vue';
  const wrapperClass = 'baf-modal';
  const closedClass = 'baf-modal-closed';
  defineOptions({ name: 'BafModal', inheritAttrs: false });
  const props = defineProps({
    ...dialogProps,
    appendToBody: {
      type: Boolean,
      default: true
    },
    // 标题栏样式
    headerStyle: {
      type: Object,
      default: () => ({})
    },
    // 标题样式
    titleStyle: {
      type: Object,
      default: () => ({})
    },
    // 主体样式
    bodyStyle: {
      type: Object,
      default: () => ({})
    },
    // 底栏样式
    footerStyle: {
      type: Object,
      default: () => ({})
    },
    // 自定义关闭按钮样式
    closeBtnStyle: {
      type: Object,
      default: () => ({})
    }
  });
  const emit = defineEmits(dialogEmits);
  /** 弹窗组件 */
  const dialogRef = ref(null);
  /** 弹窗类名 */
  const dialogClass = computed(() => {
    const classes = [wrapperClass];
    // 关闭状态
    if (!props.modelValue) {
      classes.push(closedClass);
    }
    // 自定义类名
    if (props.modalClass) {
      classes.push(props.modalClass);
    }
    return classes.join(' ');
  });
  /** 弹窗插入位置 */
  const teleportTo = computed(() => {
    return props.appendTo || 'body';
  });
  /** 禁用弹窗插入其它位置 */
  const teleportDisabled = computed(() => {
    const appendTo = props.appendTo || 'body';
    const disabled = appendTo === 'body' ? !props.appendToBody : false;
    return disabled;
  });
  /** 更新显示状态 */
  const updateModelValue = (modelValue) => {
    emit('update:modelValue', modelValue);
  };
  /** 打开的回调 */
  const handleOpen = () => {
    emit('open');
  };

  /** 打开动画结束的回调 */
  const handleOpened = () => {
    emit('opened');
  };

  /** 关闭的回调 */
  const handleClose = () => {
    emit('close');
  };

  /** 关闭动画结束的回调 */
  const handleClosed = () => {
    emit('closed');
  };

  /** 内容获取焦点的回调 */
  const handleOpenAutoFocus = () => {
    emit('openAutoFocus');
  };

  /** 内容失去焦点的回调 */
  const handleCloseAutoFocus = () => {
    emit('closeAutoFocus');
  };

  defineExpose({
    dialogRef
  });
</script>
<style lang="scss">
  .baf-modal {
    &.el-overlay {
      height: auto;
    }
    & > .el-overlay-dialog {
      position: absolute;
      display: flex;
      flex-direction: column;
      justify-content: flex-start;
      align-items: center;
      & > .el-dialog {
        padding: 0;
        flex-shrink: 0;
        position: relative;
        background: #ffffff;
        border-radius: 8px;
        margin-bottom: 16px;
        & > .el-dialog__header,
        & > .el-dialog__footer {
          flex-shrink: 0;
          border: none;
          padding: 0;
          margin: 0;
        }

        & > .el-dialog__body {
          padding: 0;
          color: inherit;
          font-size: inherit;
        }
      }
    }
  }
  /* header */
  .baf-modal-header {
    display: flex;
    align-items: center;
    box-sizing: border-box;
    padding: 18px 20px 12px 20px;
    border-bottom: none;
  }

  .baf-modal-title {
    flex: 1;
    color: rgba(0, 0, 0, 0.92);
    font-size: 16px;
    line-height: 24px;
    font-weight: bold;
    box-sizing: border-box;
  }
  /* 图标按钮 */
  .baf-modal-close {
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    line-height: 22px;
    color: rgba(0, 0, 0, 0.6);
    font-size: 16px;
    border-radius: 4px;
    box-sizing: border-box;
    cursor: pointer;

    &:hover {
      color: #409eff;
      font-weight: bold;
    }

    & + .baf-modal-close {
      margin-left: 8px;
    }
  }
  /* body */
  .baf-modal-body {
    padding: 16px 22px 24px 22px;
    box-sizing: border-box;
  }

  /* footer */
  .baf-modal-footer {
    padding: 8px 20px 18px 20px;
    border-top: none;
    box-sizing: border-box;
  }
</style>
